package com.pz.gulimall.member.service.impl;

import com.alibaba.druid.util.StringUtils;
import com.pz.gulimall.common.exception.BizCodeEnum;
import com.pz.gulimall.common.exception.RRException;
import com.pz.gulimall.common.to.RegisterMemberTo;
import com.pz.gulimall.common.to.UserInfoTo;
import com.pz.gulimall.common.utils.R;
import com.pz.gulimall.member.entity.*;
import com.pz.gulimall.member.entity.resultMaps.MemberFocusResultMap;
import com.pz.gulimall.member.service.*;
import com.pz.gulimall.member.utils.RedisUtil;
import com.pz.gulimall.member.vo.MemberFocusSearchReqVo;
import com.pz.gulimall.member.vo.MemberSearchResVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pz.gulimall.common.utils.PageUtils;
import com.pz.gulimall.common.utils.Query;

import com.pz.gulimall.member.dao.MemberDao;
import org.springframework.transaction.annotation.Transactional;


@Service("memberService")
public class MemberServiceImpl extends ServiceImpl<MemberDao, MemberEntity> implements MemberService {
    @Autowired
    private MemberLevelService memberLevelService;
    @Autowired
    private ThreadPoolExecutor executor;
    @Autowired
    private MemberStatisticsInfoService memberStatisticsInfoService;
    @Autowired
    private MemberReceiveAddressService receiveAddressService;
    @Autowired
    private MemberFocusService memberFocusService;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<MemberEntity> page = this.page(
                new Query<MemberEntity>().getPage(params),
                new QueryWrapper<>()
        );

        return new PageUtils(page);
    }

    @Override
    @Transactional
    public void saveRegister(RegisterMemberTo member) throws ExecutionException, InterruptedException {
        //判断 username 是否重复
        CompletableFuture<Long> usernameFuture = CompletableFuture.supplyAsync(() -> this.count(new QueryWrapper<MemberEntity>().eq("username", member.getUsername())), executor);
        //判断 mobile 是否重复
        CompletableFuture<Long> mobileFuture = CompletableFuture.supplyAsync(() -> this.count(new QueryWrapper<MemberEntity>().eq("mobile", member.getMobile())), executor);

        CompletableFuture.allOf(usernameFuture, mobileFuture);

        long usernameCount = usernameFuture.get();
        long mobileCount = mobileFuture.get();

        if(usernameCount>0){
            throw new RRException(BizCodeEnum.MEMBER_REGISTER_EXISTED_USERNAME.getMsg(), BizCodeEnum.MEMBER_REGISTER_EXISTED_USERNAME.getCode());
        }

        if(mobileCount>0){
            throw new RRException(BizCodeEnum.MEMBER_REGISTER_EXISTED_MOBILE.getMsg(), BizCodeEnum.MEMBER_REGISTER_EXISTED_MOBILE.getCode());
        }

        MemberEntity memberEntity = new MemberEntity();
        BeanUtils.copyProperties(member, memberEntity);
        MemberLevelEntity defaultStatus = memberLevelService.getOne(new QueryWrapper<MemberLevelEntity>().eq("default_status", 1));
        memberEntity.setNickname("新用户");
        //设置默认头像
        memberEntity.setHeader("https://img1.baidu.com/it/u=2413336595,3379219399&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500");
        memberEntity.setLevelId(defaultStatus.getId());
        memberEntity.setIntegration(0);
        memberEntity.setGrowth(0);
        memberEntity.setCreateTime(new Date());
        memberEntity.setStatus(1);
        memberEntity.setSourceType(0);

        //密码加密 TODO MD5盐值加密
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        memberEntity.setPassword(passwordEncoder.encode(memberEntity.getPassword()));
        this.save(memberEntity);

        //保存静态信息
        MemberStatisticsInfoEntity statisticsInfoEntity = new MemberStatisticsInfoEntity();
        statisticsInfoEntity.setMemberId(memberEntity.getId());
        memberStatisticsInfoService.save(statisticsInfoEntity);
    }

    @Override
    public R queryMember(String id) {
        MemberEntity member = this.getOne(new QueryWrapper<MemberEntity>()
                .eq("username", id)
                .or().eq("mobile", id)
                .or().eq("email", id));
        return member == null ?
                R.error(BizCodeEnum.MEMBER_DONT_EXISTED.getCode(), BizCodeEnum.MEMBER_DONT_EXISTED.getMsg()) :
                R.ok().put("pwd", member.getPassword()).put("data", member);
    }

    /**
     * @param id ums_member id 用户数据库唯一标识
     */
    @Override
    public R queryUserInfoById(Long id) {
        UserInfoTo userInfoTo = new UserInfoTo();
        CompletableFuture<MemberEntity> task1 = CompletableFuture.supplyAsync(() -> getById(id), executor);
        CompletableFuture<List<MemberReceiveAddressEntity>> task2 = CompletableFuture.supplyAsync(() -> receiveAddressService.list(new QueryWrapper<MemberReceiveAddressEntity>().eq("member_id", id)), executor);
        CompletableFuture<MemberStatisticsInfoEntity> task3 = CompletableFuture.supplyAsync(() -> memberStatisticsInfoService.getOne(new QueryWrapper<MemberStatisticsInfoEntity>().eq("member_id", id)), executor);

        CompletableFuture.allOf(task1, task2, task3);
        MemberEntity member = null;
        List<MemberReceiveAddressEntity> memberReceiveAddressEntities = null;
        MemberStatisticsInfoEntity statisticsInfoEntity = null;
        try {
            member = task1.get();
            memberReceiveAddressEntities = task2.get();
            statisticsInfoEntity = task3.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
            throw new RRException(BizCodeEnum.THREAD_EXCEPTION.getMsg()+e.getMessage(), BizCodeEnum.THREAD_EXCEPTION.getCode());
        }

        BeanUtils.copyProperties(member, userInfoTo);
        BeanUtils.copyProperties(statisticsInfoEntity, userInfoTo);
        List<UserInfoTo.ReceiveAddress> address = new ArrayList<>();
        memberReceiveAddressEntities.forEach(item -> {
            UserInfoTo.ReceiveAddress receiveAddress = new UserInfoTo.ReceiveAddress();
            BeanUtils.copyProperties(item, receiveAddress);
            address.add(receiveAddress);
        });
        userInfoTo.setReceiveAddresses(address);
        BeanUtils.copyProperties(member, userInfoTo);

        return R.ok().put("data", userInfoTo);
    }

    @Override
    @Transactional
    public void updateUserInfo(UserInfoTo userInfo) {
        //更新地址数据 ums_member_receive_address
        if(userInfo.getReceiveAddresses()!=null && !userInfo.getReceiveAddresses().isEmpty()){
            userInfo.getReceiveAddresses().forEach(address -> {
                MemberReceiveAddressEntity receiveAddressEntity = new MemberReceiveAddressEntity();
                BeanUtils.copyProperties(address, receiveAddressEntity);
                receiveAddressService.updateById(receiveAddressEntity);
            });
        }

        //TODO 更新基本数据 ums_member

        //TODO 更新静态数据
    }

    @Override
    public R queryMemberFocus(MemberFocusSearchReqVo vo) {
        if(vo.getType().equals("my-focus")) {
            // 搜索自己的关注列表
            List<MemberFocusResultMap> memberFocus;
            if(StringUtils.isEmpty(vo.getKey())) {
                memberFocus = this.baseMapper.queryMyFocus(vo.getUserId(), null);
            } else {
                memberFocus = this.baseMapper.queryMyFocus(vo.getUserId(), vo.getKey());
            }
            return R.ok().put("data", memberFocus);
        }
        if(vo.getType().equals("add-focus") && !StringUtils.isEmpty(vo.getKey())) {
            // 全局搜索用户
            //member.nickname LIKE '%test%' OR mem.username LIKE '%test%' OR mem.mobile = '' OR mem.email = ''
            List<MemberEntity> list = this.list(new QueryWrapper<MemberEntity>()
                    .like("nickname", vo.getKey())
                    .or().like("username", vo.getKey())
                    .or().eq("mobile", vo.getKey())
                    .or().eq("email", vo.getKey())
            );
            List<MemberSearchResVo> ans = new ArrayList<>();
            for (MemberEntity member : list) {
                // 把自己排除掉
                if (member.getId().longValue() != vo.getUserId()){
                    MemberSearchResVo temp = new MemberSearchResVo();
                    temp.setUserId(vo.getUserId());
                    BeanUtils.copyProperties(member, temp);

                    MemberFocusEntity one = memberFocusService.getOne(new QueryWrapper<MemberFocusEntity>()
                            .eq("from_member_id", temp.getUserId())
                            .and(q -> q.eq("to_member_id", member.getId())));
                    if(one == null){
                        temp.setFocusStatus(2);
                    } else {
                        temp.setFocusStatus(one.getAck());
                    }
                    ans.add(temp);
                }
            }
            return R.ok().put("data", ans);
        } else if (StringUtils.isEmpty(vo.getKey())) {
            return R.ok();
        }
        throw new RRException(BizCodeEnum.MEMBER_SEARCH_TYPE_ILLEGAL);
    }

    private static final String channelIdRegisterPrefix = "ClientServerBind::";
    @Override
    public R getChannelRegisterId(Long userId) {
        MemberEntity member = getById(userId);
        if(redisUtil.hasKey(channelIdRegisterPrefix+member.getMobile())) {
            return R.okData(member.getMobile());
        } else if(redisUtil.hasKey(channelIdRegisterPrefix+member.getEmail())) {
            return R.okData(member.getEmail());
        } else if (redisUtil.hasKey(channelIdRegisterPrefix+member.getUsername())) {
            return R.okData(member.getUsername());
        } else {
            return R.okData(-1);
        }
    }
}